package com.m3839.sdk.common.widget.floatview;

import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * Description:HykbFloatView
 *
 * @author chenbaoyang
 * @create 2019/12/30 14: 48
 */
public class HykbFloatView {

  private static final Handler HANDLER = new Handler(Looper.getMainLooper());

  /** 上下文 */
  private Context mContext;
  /** 根布局 */
  private View mRootView;
  /** 悬浮窗口 */
  private WindowManager mWindowManager;
  /** 窗口参数 */
  private WindowManager.LayoutParams mWindowParams;

  /** 当前是否已经显示 */
  private boolean mShow;
  /** 窗口显示时长 */
  private int mDuration;

  private HykbFloatView(Context context) {
    mContext = context;
    mWindowManager = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE));

    mWindowParams = new WindowManager.LayoutParams();
    // 配置一些默认的参数
    mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
    mWindowParams.format = PixelFormat.TRANSLUCENT;
    mWindowParams.windowAnimations = android.R.style.Animation_Toast;
    mWindowParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    mWindowParams.packageName = context.getPackageName();
  }

  /**
   * 创建一个局部悬浮窗
   */
  public HykbFloatView(Activity activity) {
    this((Context) activity);

    // 如果当前 Activity 是全屏模式，那么添加这个标记，否则会导致 WindowManager 在某些机型上移动不到状态栏位置上
    if ((activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
      addWindowFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

  }

  /**
   * 设置动画样式
   */
  public HykbFloatView setAnimStyle(int id) {
    mWindowParams.windowAnimations = id;
    if (isShow()) {
      update();
    }
    return this;
  }


  /**
   * 添加一个标志位
   */
  public HykbFloatView addWindowFlags(int flags) {
    mWindowParams.flags |= flags;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 是否有这个标志位
   */
  public boolean hasWindowFlags(int flags) {
    return (mWindowParams.flags & flags) != 0;
  }

  /**
   * 移除一个标志位
   */
  public HykbFloatView removeWindowFlags(int flags) {
    mWindowParams.flags &= ~flags;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 根据 ViewId 获取 View
   */
  public <V extends View> V findViewById(int id) {
    if (mRootView == null) {
      throw new IllegalStateException("Please setup view");
    }
    return (V) mRootView.findViewById(id);
  }

  public HykbFloatView setText(int viewId, int stringId) {
    return setText(viewId, mContext.getResources().getString(stringId));
  }

  public HykbFloatView setText(CharSequence text) {
    return setText(android.R.id.message, text);
  }

  public HykbFloatView setText(int id, CharSequence text) {
    ((TextView) findViewById(id)).setText(text);
    return this;
  }

  public HykbFloatView setVisible(int viewId, int visibility) {
    findViewById(viewId).setVisibility(visibility);
    return this;
  }

  /**
   * 设置点击事件
   */
  public HykbFloatView setOnClickListener(int id, OnClickListener listener) {
    new ViewClickWrapper(this, findViewById(id), listener);
    // 当前是否设置了不可触摸，如果是就擦除掉
    if (hasWindowFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)) {
      removeWindowFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
      if (isShow()) {
        update();
      }
    }
    return this;
  }

  /**
   * 设置 X 轴偏移量
   */
  public HykbFloatView setXOffset(int x) {
    mWindowParams.x = x;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 设置 Y 轴偏移量
   */
  public HykbFloatView setYOffset(int y) {
    mWindowParams.y = y;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 设置重心
   */
  public HykbFloatView setGravity(int gravity) {
    mWindowParams.gravity = gravity;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 设置宽度
   */
  public HykbFloatView setWidth(int width) {
    mWindowParams.width = width;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 设置高度
   */
  public HykbFloatView setHeight(int height) {
    mWindowParams.height = height;
    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 限定显示时长
   */
  public HykbFloatView setDuration(int duration) {
    mDuration = duration;
    if (isShow()) {
      if (mDuration != 0) {
        removeCallbacks();
        postDelayed(new DismissRunnable(this), mDuration);
      }
    }
    return this;
  }


  /**
   * 设置布局
   */
  public HykbFloatView setView(int id) {
    return setView(LayoutInflater.from(mContext).inflate(id, new FrameLayout(mContext), false));
  }

  public HykbFloatView setView(View view) {
    mRootView = view;

    ViewGroup.LayoutParams params = mRootView.getLayoutParams();
    if (params != null && mWindowParams.width == WindowManager.LayoutParams.WRAP_CONTENT &&
        mWindowParams.height == WindowManager.LayoutParams.WRAP_CONTENT) {
      // 如果当前 Dialog 的宽高设置了自适应，就以布局中设置的宽高为主
      setWidth(params.width);
      setHeight(params.height);
    }

    // 如果当前没有设置重心，就自动获取布局重心
    if (mWindowParams.gravity == Gravity.NO_GRAVITY) {
      if (params instanceof FrameLayout.LayoutParams) {
        setGravity(((FrameLayout.LayoutParams) params).gravity);
      } else if (params instanceof LinearLayout.LayoutParams) {
        setGravity(((LinearLayout.LayoutParams) params).gravity);
      } else {
        // 默认重心是居中
        setGravity(Gravity.CENTER);
      }
    }

    if (isShow()) {
      update();
    }
    return this;
  }

  /**
   * 显示
   */
  public HykbFloatView show() {
    if (mRootView == null || mWindowParams == null) {
      throw new IllegalArgumentException("WindowParams and view cannot be empty");
    }

    // 如果当前已经显示取消上一次显示
    if (mShow) {
      cancel();
    }
    try {
      // 如果这个 View 对象被重复添加到 WindowManager 则会抛出异常
      // java.lang.IllegalStateException: View android.widget.TextView{3d2cee7 V.ED..... ......ID 0,0-312,153} has already been added to the window manager.
      mWindowManager.addView(mRootView, mWindowParams);
      // 当前已经显示
      mShow = true;
      // 如果当前限定了显示时长
      if (mDuration != 0) {
        postDelayed(new DismissRunnable(this), mDuration);
      }

    } catch (NullPointerException | IllegalStateException | WindowManager.BadTokenException e) {
      e.printStackTrace();
    }

    return this;
  }

  /**
   * 取消
   */
  public HykbFloatView cancel() {
    if (mShow) {
      try {


        // 如果当前 WindowManager 没有附加这个 View 则会抛出异常
        // java.lang.IllegalArgumentException: View=android.widget.TextView{3d2cee7 V.ED..... ........ 0,0-312,153} not attached to window manager
        mWindowManager.removeView(mRootView);

      } catch (NullPointerException | IllegalArgumentException | IllegalStateException e) {
        e.printStackTrace();
      }
      // 当前没有显示
      mShow = false;
    }

    return this;
  }


  /**
   * 更新
   */
  public void update() {
    // 更新 WindowManger 的显示
    mWindowManager.updateViewLayout(mRootView, mWindowParams);
  }

  /**
   * 当前是否已经显示
   */
  public boolean isShow() {
    return mShow;
  }


  /**
   * 延迟一段时间执行
   */
  public boolean postDelayed(Runnable r, long delayMillis) {
    if (delayMillis < 0) {
      delayMillis = 0;
    }
    return postAtTime(r, SystemClock.uptimeMillis() + delayMillis);
  }

  /**
   * 在指定的时间执行
   */
  public boolean postAtTime(Runnable r, long uptimeMillis) {
    // 发送和这个 WindowManager 相关的消息回调
    return HANDLER.postAtTime(r, this, uptimeMillis);
  }

  /**
   * 移除消息回调
   */
  public void removeCallbacks() {
    HANDLER.removeCallbacksAndMessages(this);
  }


}
